<?php

/**
 * WeEngine Api System
 *
 * (c) We7Team 2019 <https://www.w7.cc>
 *
 * This is not a free software
 * Using it under the license terms
 * visited https://www.w7.cc for more details
 */

namespace W7\Sdk\VSCode\Domain;

use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File as Fs;
use Illuminate\Support\Facades\Storage;
use W7\Sdk\VSCode\Exceptions\FileExistsException;
use W7\Sdk\VSCode\Exceptions\FileNotFoundException;

class File {
	/**
	 * @var string
	 */
	private $uri;
	/**
	 * @var string
	 */
	private $disk = '';

	/**
	 * @var Filesystem
	 */
	private $filesystem;

	public function __construct(string $uri, Filesystem $filesystem = null) {
		$this->uri = $uri;
		if (is_null($filesystem)) {
			$this->disk = config('w7-vscode.driver', 'local');
			$this->filesystem = Storage::disk($this->disk);
		}
	}

	public static function make(string $uri) {
		return new static($uri);
	}

	public function isDirectory() {
		$fulluri = $this->getUrl();
		return Fs::isDirectory($fulluri);
	}

	public function isFile() {
		$fulluri = $this->getUrl();
		return Fs::isFile($fulluri);
	}

	public function exists() {
		return $this->filesystem->exists($this->uri);
	}

	public function getUri() : string {
		return $this->uri;
	}

	public function getUrl() : string {
		return $this->filesystem->path($this->uri);
	}

	public function makeDirectory() {
		return $this->filesystem->makeDirectory($this->uri);
	}

	public function createDirectory() {
		return $this->makeDirectory();
	}

	public function delete() : bool {
		$this->assertExists();
		if ($this->isDirectory()) {
			return $this->filesystem->deleteDirectory($this->uri);
		}
		return $this->filesystem->delete($this->uri);
	}

	public function readDirectory() : Collection {
		$files = $this->filesystem->files($this->uri);
		$dirs = $this->filesystem->directories($this->uri);
		$files = collect($files)->map(function ($file) {
			$file = pathinfo($file, PATHINFO_BASENAME);
			return [$file, 1];
		})->filter(function ($item) {
			return $item[0] != ''; //
		});
		$dirs = collect($dirs)->map(function ($dir) {
			$dir = pathinfo($dir, PATHINFO_FILENAME);
			return [$dir, 2];
		})->filter(function ($item) {
			return $item[0] != ''; //
		});
		return $files->merge($dirs);
	}

	public function get() : string {
		$this->assertExists();
		return $this->filesystem->get($this->uri);
	}

	public function write(string $content) {
		if ($this->isDirectory()) {
			throw new FileExistsException();
		}
		$this->filesystem->put($this->uri, $content);
	}

	/**
	 * @return array
	 */
	public function stat() {
		if ($this->uri === '/') {
			return [
				'size'=> 0,
				'type'=> 2,
				'mtime' => time(),
				'ctime' => time(),
				'isSymbolicLink' => false,
				'uri' => $this->uri,
			];
		}
		return [
			'size'=>$this->isFile() ? $this->filesystem->size($this->uri) : 0,
			'type'=>$this->isDirectory() ? 2 : 1,
			'mtime' => $this->filesystem->lastModified($this->uri),
			'ctime' => $this->filesystem->lastModified($this->uri),
			'isSymbolicLink' => false,
			'uri' => $this->uri,
		];
	}
	/**
	 * @param string $newUri
	 */
	public function copyTo(string $newUri) : File {
		$fromFile = File::make($this->uri);
		$toFile = File::make($newUri);
		if (!$fromFile->exists()) {
			throw new FileNotFoundException($fromFile->getUri());
		}

		if ($fromFile->isDirectory()) {
			$toFile->makeDirectory();
			if (!$toFile->exists()) {
				$toFile->makeDirectory();
			}
			Fs::copyDirectory($fromFile->getUrl(), $toFile->getUrl());
		}
		if ($fromFile->isFile()) {
			$this->filesystem->copy($this->uri, $newUri);
		}
		return $toFile;
	}

	public function rename(string $newUri) : File {
		$fromFile = File::make($this->uri);
		$toFile = File::make($newUri);

		$this->assertExists();

		$this->filesystem->move($this->uri, $newUri);
		return $toFile;
	}

	private function assertExists() {
		if (! $this->exists()) {
			throw new FileNotFoundException($this->uri);
		}
	}
}
